package com.bytz.modules.cms.order.service.impl;

import cn.hutool.core.util.NumberUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bytz.common.exception.BytzBootException;
import com.bytz.modules.cms.order.constant.OfflinePayConstants;
import com.bytz.modules.cms.order.entity.OrderOfflinePay;
import com.bytz.modules.cms.order.entity.OrderPayDetail;
import com.bytz.modules.cms.order.mapper.OrderOfflinePayMapper;
import com.bytz.modules.cms.order.service.IOrderOfflinePayService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import static com.bytz.modules.cms.order.constant.OfflinePayConstants.OfflinePayStatus.AVAILABLE;
import static com.bytz.modules.cms.order.constant.OfflinePayConstants.OfflinePayStatus.DONE;

/**
 * <p>
 * 莱宝CMS—订单管理-订单线下支付信息表 服务实现类
 * </p>
 *
 * @author KyleWang
 * @since 2022-10-10
 */
@Service
public class OrderOfflinePayServiceImpl extends ServiceImpl<OrderOfflinePayMapper, OrderOfflinePay> implements IOrderOfflinePayService {

    @Override
    public List<OrderOfflinePay> getByIds(Collection<String> ids) {
        return lambdaQuery().in(OrderOfflinePay::getId, ids).list();
    }

    @Override
    public void checkCanPay(List<OrderOfflinePay> orderOfflinePays) {
        for (OrderOfflinePay orderOfflinePay : orderOfflinePays) {
            // 是否可用
            if (!AVAILABLE.equals(orderOfflinePay.getStatus())) {
                throw new BytzBootException("【" + orderOfflinePay.getRemitName() + "】不可用");
            }

            // 是否生效
            if (orderOfflinePay.getEffectTime() != null && !orderOfflinePay.getEffectTime().isBefore(LocalDateTime.now())) {
                throw new BytzBootException("【" + orderOfflinePay.getRemitName() + "】未生效");
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void lockOfflinePays(List<OrderOfflinePay> offlinePays) {
        for (OrderOfflinePay offlinePay : offlinePays) {
            lambdaUpdate()
                    .set(OrderOfflinePay::getStatus, OfflinePayConstants.OfflinePayStatus.LOCKED)
                    .eq(OrderOfflinePay::getId, offlinePay.getId())
                    .update();
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void submitPay(List<OrderPayDetail> offlinePayDetails) {
        Set<String> offlinePayIdset = offlinePayDetails.stream()
                .map(OrderPayDetail::getOfflinePayId)
                .collect(Collectors.toSet());

        List<OrderOfflinePay> offlinePays = getByIds(offlinePayIdset);

        submitPay(offlinePayDetails, offlinePays);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void submitPay(List<OrderPayDetail> offlinePayDetails, List<OrderOfflinePay> offlinePays) {
        Map<String, BigDecimal> offlinePayAmountMap = offlinePayDetails.stream()
                .collect(Collectors.toMap(OrderPayDetail::getOfflinePayId, OrderPayDetail::getPayAmount));

        for (OrderOfflinePay offlinePay : offlinePays) {
            BigDecimal payAmount = offlinePayAmountMap.get(offlinePay.getId());
            if (payAmount == null) {
                throw new BytzBootException("找不到汇票【" + offlinePay.getRemitName() + "】对应的支付记录");
            }

            // 计算支付完余额
            BigDecimal remainAmount = offlinePay.getRemainAmount().subtract(payAmount);
            // 计算汇票状态
            String status = NumberUtil.equals(BigDecimal.ZERO, remainAmount) ? DONE : AVAILABLE;

            lambdaUpdate()
                    .set(OrderOfflinePay::getRemainAmount, remainAmount)
                    .set(OrderOfflinePay::getStatus, status)
                    .eq(OrderOfflinePay::getId, offlinePay.getId())
                    .update();
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void releaseOfflinePay(List<OrderPayDetail> offlinePayDetails) {
        Set<String> offlinePayIds = offlinePayDetails.stream()
                .map(OrderPayDetail::getOfflinePayId)
                .collect(Collectors.toSet());

        lambdaUpdate()
                .set(OrderOfflinePay::getStatus, AVAILABLE)
                .in(OrderOfflinePay::getId, offlinePayIds)
                .update();
    }
}
